package com.sunwayworld.basemodule.common.eptstorage.acqconfig.net;

import com.sunwayworld.basemodule.common.eptstorage.acqconfig.bean.LimsEquiptAcqConfigInstBean;
import com.sunwayworld.basemodule.common.eptstorage.acqconfig.bean.LimsEquiptSerialNetRecBean;
import com.sunwayworld.basemodule.common.eptstorage.acqconfig.service.LimsEquiptSerialNetRecService;
import com.sunwayworld.basemodule.common.eptstorage.equiptacqschedule.bean.LimsEquiptAcqScheduleTaskBean;
import com.sunwayworld.basemodule.common.eptstorage.equiptacqschedule.service.impl.LimsEquiptAcqScheduleTaskServiceImpl;
import com.sunwayworld.basemodule.common.eptstorage.util.Util;
import com.sunwayworld.cloud.module.equipt.acqconfig.bean.CoreEquiptAcqConfigBean;
import com.sunwayworld.framework.cache.redis.RedisHelper;
import com.sunwayworld.framework.constant.Constant;
import com.sunwayworld.framework.context.ApplicationContextHelper;
import com.sunwayworld.framework.exception.InvalidDataException;
import com.sunwayworld.framework.utils.ObjectUtils;
import com.sunwayworld.framework.utils.StringUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.time.LocalDateTime;
import java.util.Queue;

/**
 * @auther zhangs
 * @description
 * @date 2022/3/4
 */
public abstract class NetEptSender{
    private static final Logger logger = LogManager.getLogger(NetEptSender.class);
    private CoreEquiptAcqConfigBean eptAcqBean;
    private Thread readThread;
    public volatile boolean connect=false;
    public static final int writeAndFlushWaitSecond = 2;
    public static final int readWaitSecond = 2;
    public static final int waitConnectSecond = 2;

    public NetEptSender(CoreEquiptAcqConfigBean eptAcqBean) {
        this.eptAcqBean = eptAcqBean;
    }


    public abstract boolean getConnection();

    public abstract String send(LimsEquiptAcqConfigInstBean instBean);

    public abstract void close();

    public boolean isConnect() {
        return connect;
    }

    public void setConnect(boolean connect) {
        this.connect = connect;
    }

    public CoreEquiptAcqConfigBean getEptAcqBean() {
        return eptAcqBean;
    }

    public static Logger getLogger() {
        return logger;
    }
    static String getKey(CoreEquiptAcqConfigBean configBean){
        return configBean.getIp()+":"+configBean.getPort();
    }

    public void startAsyncSequenceReadQueueAndSendWhenActive(){
        NetEptSenderHelper.failClear(eptAcqBean);

        String host = eptAcqBean.getIp();
        int port = Integer.parseInt(eptAcqBean.getPort());
        String key = host+":"+port;
        readThread = new Thread(() -> {
            logger.info("为设备={},所在线程ID={},循环取指令发送.........", key, readThread.getId());
            while(isConnect()) {
                try {//只要设备连接还在，循环就不能终止
                    Queue<LimsEquiptAcqConfigInstBean> queue = NetEptSenderHelper.eptInstMap.get(key);
                    LimsEquiptAcqConfigInstBean configInstBean = null;
                    String resultSaveType = "";
                    if (queue != null && queue.size()>0) {
                        LimsEquiptAcqScheduleTaskBean taskBean = new LimsEquiptAcqScheduleTaskBean();
                        taskBean.setCreatedTime(LocalDateTime.now());
                        try {
                            configInstBean = queue.poll();
                            if (configInstBean != null) {
                                logger.info("设备={},所在线程ID={},指令={},正在发送指令.........", key, readThread.getId(),configInstBean.getInstruction());
                                resultSaveType = configInstBean.getResultSaveType();
                                taskBean.setAcqType(configInstBean.getInstructionType());
                                taskBean.setEquiptId(configInstBean.getAcqConfigId());
                                String acqData = send(configInstBean);
                                taskBean.setAcqData(acqData);
                                taskBean.setResult("success");
                            }
                            Thread.sleep(500); //每0.5s取一次指令
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            logger.error("连接={},循环线程={},指令={},发送指令失败..........", key, readThread.getId(), configInstBean.getInstruction());
                            taskBean.setResult("fail");
                            taskBean.setErrorMsg(e.getMessage());
//                    setConnect(false);
                        }
                        //根据数据存储方式不一样，做不同的存储操作
                        /*MailUtil mailUtil = ApplicationContextHelper.getBean(MailUtil.class);
                        mailUtil.send(taskBean);*/
                        if ("allData".equals(resultSaveType)) {
                            taskBean.setId(ApplicationContextHelper.getNextIdentity());
                            ApplicationContextHelper.getBean(LimsEquiptAcqScheduleTaskServiceImpl.class).getDao().insert(taskBean);
                        } else {
                            RedisHelper.put("EQUIPT_RETURN_DATA", configInstBean.getId().toString(), taskBean);
                        }
                    }
                }catch (Exception e){
                    e.printStackTrace();
                    logger.info("循环发送指令时出错  连接={},循环线程={}..........", key, readThread.getId());
                    close();
                }
            }
            Thread thread = Thread.currentThread();
            getLogger().error( "{},{}---read interrupt--------->remoteAddress={}",thread.getId(),thread.getName(),key);
        });
        readThread.setName("readThread:"+key);
        readThread.start();
        logger.info("为连接={},启动循环线程={},{}..........",key,readThread.getName(),readThread.getId());
    }

    public String insertMsg(LimsEquiptAcqConfigInstBean configInstBean,Object msg){
        CoreEquiptAcqConfigBean eptAcqBean = getEptAcqBean();
        String host = eptAcqBean.getIp();
        int port = Integer.parseInt(eptAcqBean.getPort());
        getLogger().info("channelRead:msg type is {},msg is {},from {}", msg.getClass(), msg, (host + ":" + port));

        String hixFlag = configInstBean.getHixFlag();
        LimsEquiptSerialNetRecBean netRecBean = new LimsEquiptSerialNetRecBean();
        netRecBean.setEquiptId(Long.parseLong(configInstBean.getAcqConfigId()));
        netRecBean.setAcqCategory(configInstBean.getExt$Item("acqcategory"));
        netRecBean.setDataUseType(configInstBean.getInstructionType());
        netRecBean.setLabArea(configInstBean.getExt$Item("labarea"));
        netRecBean.setEptLabType(configInstBean.getExt$Item("eptlabtype"));
        netRecBean.setId(ApplicationContextHelper.getNextIdentity());
        String body = "";
        try {
            if (msg instanceof String) {
                body = ObjectUtils.toString(msg);
            } else if (msg instanceof ByteBuf) {
                //字节转16进制字符串
                if (StringUtils.equalsIgnoreCase(Constant.YES,hixFlag)) {
                    body = ByteBufUtil.hexDump((ByteBuf) msg);
                }else{
                    body = Util.convert2String((ByteBuf) msg, "UTF-8");
                }
            }
        }catch (Exception s){
            getLogger().error("---------->msg={} convert error={}",msg,s);
            throw new InvalidDataException("数据类型转化失败");
        }
        if (ObjectUtils.isEmpty(body)) {
            return "fail";
        }
        getLogger().info("read from remote={},msg={}", (host + ":" + port), body);
        netRecBean.setAcqData(body); //返回的数据
        try {
            Object result = Util.analysisBsh(body,configInstBean.getExt$Item("script"));
            netRecBean.setAnalyseData(ObjectUtils.toString(result)); //解析后的数据
        } catch (Exception s) {
            netRecBean.setAnalyseData(""); //解析后的数据
            getLogger().error("---------->analysisBsh error={}", s);
            throw new InvalidDataException("返回数据解析失败");
        }
        ApplicationContextHelper.getBean(LimsEquiptSerialNetRecService.class).getDao().insert(netRecBean);
        return netRecBean.getAnalyseData();
    }

    public void cacheSender(){
        NetEptSenderHelper.putNetEptSender(eptAcqBean,this); //连接active后，缓存sender
    }
    public void removeCacheSender(){
        NetEptSenderTest.removeNetEptSender(eptAcqBean); //连接失败，移除
    }

//    public static void main (String arg[]){
//        String $content$ = "00000000000701030442AAD554";
//        if (!ObjectUtils.isEmpty($content$)){
//            String sub = $content$.substring(18,26);
//            Float temperature = Float.intBitsToFloat(new BigInteger(sub, 16).intValue());
//            System.out.println(temperature.toString());
//        }else{
//            return "";
//        }
//    }
}
